{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1"
      },
      "source": [
        "# Langmem with MongoDB: Building Conversational Memory\n",
        "\n",
        "---\n",
        "\n",
        "This notebook demonstrates how to use `langmem` with `langgraph` and MongoDB to build a conversational agent that can remember information across interactions.\n",
        "\n",
        "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/mongodb-developer/GenAI-Showcase/blob/main/notebooks/memory/langmem_mongodb_notebook.ipynb)\n",
        "\n",
        "[![View Article](https://img.shields.io/badge/View%20Article-blue)](https://dev.to/mongodb/langgraph-with-mongodb-building-conversational-long-term-memory-for-intelligent-ai-agents-2pcn)\n",
        "\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2"
      },
      "source": [
        "## Use Case: A Simple Preference-Aware Assistant\n",
        "\n",
        "We will build a simple assistant that can remember a user's preferences (like their preferred display mode) and recall them in the same or different conversations."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3"
      },
      "source": [
        "### Part 1: Setup and Dependencies\n",
        "\n",
        "First, let's install the required Python libraries."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "4",
        "outputId": "8ecb3b20-6497-4ca0-c898-d252a72808c7"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Collecting langgraph\n",
            "  Downloading langgraph-0.6.5-py3-none-any.whl.metadata (6.8 kB)\n",
            "Collecting langmem\n",
            "  Downloading langmem-0.0.29-py3-none-any.whl.metadata (6.8 kB)\n",
            "Collecting pymongo\n",
            "  Downloading pymongo-4.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (22 kB)\n",
            "Requirement already satisfied: openai in /usr/local/lib/python3.11/dist-packages (1.99.9)\n",
            "Collecting python-dotenv\n",
            "  Downloading python_dotenv-1.1.1-py3-none-any.whl.metadata (24 kB)\n",
            "Requirement already satisfied: typing-extensions in /usr/local/lib/python3.11/dist-packages (4.14.1)\n",
            "Collecting langgraph-checkpoint-mongodb\n",
            "  Downloading langgraph_checkpoint_mongodb-0.1.4-py3-none-any.whl.metadata (2.6 kB)\n",
            "Collecting langchain_mongodb\n",
            "  Downloading langchain_mongodb-0.6.2-py3-none-any.whl.metadata (1.7 kB)\n",
            "Collecting langgraph-store-mongodb\n",
            "  Downloading langgraph_store_mongodb-0.0.1-py3-none-any.whl.metadata (362 bytes)\n",
            "Collecting langchain_voyageai\n",
            "  Downloading langchain_voyageai-0.1.7-py3-none-any.whl.metadata (1.2 kB)\n",
            "Requirement already satisfied: langchain-core>=0.1 in /usr/local/lib/python3.11/dist-packages (from langgraph) (0.3.74)\n",
            "Collecting langgraph-checkpoint<3.0.0,>=2.1.0 (from langgraph)\n",
            "  Downloading langgraph_checkpoint-2.1.1-py3-none-any.whl.metadata (4.2 kB)\n",
            "Collecting langgraph-prebuilt<0.7.0,>=0.6.0 (from langgraph)\n",
            "  Downloading langgraph_prebuilt-0.6.4-py3-none-any.whl.metadata (4.5 kB)\n",
            "Collecting langgraph-sdk<0.3.0,>=0.2.0 (from langgraph)\n",
            "  Downloading langgraph_sdk-0.2.0-py3-none-any.whl.metadata (1.5 kB)\n",
            "Requirement already satisfied: pydantic>=2.7.4 in /usr/local/lib/python3.11/dist-packages (from langgraph) (2.11.7)\n",
            "Requirement already satisfied: xxhash>=3.5.0 in /usr/local/lib/python3.11/dist-packages (from langgraph) (3.5.0)\n",
            "Collecting langchain-anthropic>=0.3.3 (from langmem)\n",
            "  Downloading langchain_anthropic-0.3.18-py3-none-any.whl.metadata (1.9 kB)\n",
            "Collecting langchain-openai>=0.3.1 (from langmem)\n",
            "  Downloading langchain_openai-0.3.30-py3-none-any.whl.metadata (2.4 kB)\n",
            "Requirement already satisfied: langchain>=0.3.15 in /usr/local/lib/python3.11/dist-packages (from langmem) (0.3.27)\n",
            "Requirement already satisfied: langsmith>=0.3.8 in /usr/local/lib/python3.11/dist-packages (from langmem) (0.4.14)\n",
            "Collecting trustcall>=0.0.39 (from langmem)\n",
            "  Downloading trustcall-0.0.39-py3-none-any.whl.metadata (29 kB)\n",
            "Collecting dnspython<3.0.0,>=1.16.0 (from pymongo)\n",
            "  Downloading dnspython-2.7.0-py3-none-any.whl.metadata (5.8 kB)\n",
            "Requirement already satisfied: anyio<5,>=3.5.0 in /usr/local/lib/python3.11/dist-packages (from openai) (4.10.0)\n",
            "Requirement already satisfied: distro<2,>=1.7.0 in /usr/local/lib/python3.11/dist-packages (from openai) (1.9.0)\n",
            "Requirement already satisfied: httpx<1,>=0.23.0 in /usr/local/lib/python3.11/dist-packages (from openai) (0.28.1)\n",
            "Requirement already satisfied: jiter<1,>=0.4.0 in /usr/local/lib/python3.11/dist-packages (from openai) (0.10.0)\n",
            "Requirement already satisfied: sniffio in /usr/local/lib/python3.11/dist-packages (from openai) (1.3.1)\n",
            "Requirement already satisfied: tqdm>4 in /usr/local/lib/python3.11/dist-packages (from openai) (4.67.1)\n",
            "Collecting motor>3.6.0 (from langgraph-checkpoint-mongodb)\n",
            "  Downloading motor-3.7.1-py3-none-any.whl.metadata (21 kB)\n",
            "Collecting pymongo\n",
            "  Downloading pymongo-4.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (22 kB)\n",
            "Requirement already satisfied: langchain-text-splitters>=0.3 in /usr/local/lib/python3.11/dist-packages (from langchain_mongodb) (0.3.9)\n",
            "Collecting lark<2.0.0,>=1.1.9 (from langchain_mongodb)\n",
            "  Downloading lark-1.2.2-py3-none-any.whl.metadata (1.8 kB)\n",
            "Requirement already satisfied: numpy>=1.26 in /usr/local/lib/python3.11/dist-packages (from langchain_mongodb) (2.0.2)\n",
            "Collecting voyageai<1,>=0.3.4 (from langchain_voyageai)\n",
            "  Downloading voyageai-0.3.4-py3-none-any.whl.metadata (2.9 kB)\n",
            "Requirement already satisfied: idna>=2.8 in /usr/local/lib/python3.11/dist-packages (from anyio<5,>=3.5.0->openai) (3.10)\n",
            "Requirement already satisfied: certifi in /usr/local/lib/python3.11/dist-packages (from httpx<1,>=0.23.0->openai) (2025.8.3)\n",
            "Requirement already satisfied: httpcore==1.* in /usr/local/lib/python3.11/dist-packages (from httpx<1,>=0.23.0->openai) (1.0.9)\n",
            "Requirement already satisfied: h11>=0.16 in /usr/local/lib/python3.11/dist-packages (from httpcore==1.*->httpx<1,>=0.23.0->openai) (0.16.0)\n",
            "Requirement already satisfied: SQLAlchemy<3,>=1.4 in /usr/local/lib/python3.11/dist-packages (from langchain>=0.3.15->langmem) (2.0.43)\n",
            "Requirement already satisfied: requests<3,>=2 in /usr/local/lib/python3.11/dist-packages (from langchain>=0.3.15->langmem) (2.32.3)\n",
            "Requirement already satisfied: PyYAML>=5.3 in /usr/local/lib/python3.11/dist-packages (from langchain>=0.3.15->langmem) (6.0.2)\n",
            "Collecting anthropic<1,>=0.60.0 (from langchain-anthropic>=0.3.3->langmem)\n",
            "  Downloading anthropic-0.64.0-py3-none-any.whl.metadata (27 kB)\n",
            "Requirement already satisfied: tenacity!=8.4.0,<10.0.0,>=8.1.0 in /usr/local/lib/python3.11/dist-packages (from langchain-core>=0.1->langgraph) (9.1.2)\n",
            "Requirement already satisfied: jsonpatch<2.0,>=1.33 in /usr/local/lib/python3.11/dist-packages (from langchain-core>=0.1->langgraph) (1.33)\n",
            "Requirement already satisfied: packaging>=23.2 in /usr/local/lib/python3.11/dist-packages (from langchain-core>=0.1->langgraph) (25.0)\n",
            "Requirement already satisfied: tiktoken<1,>=0.7 in /usr/local/lib/python3.11/dist-packages (from langchain-openai>=0.3.1->langmem) (0.11.0)\n",
            "Collecting ormsgpack>=1.10.0 (from langgraph-checkpoint<3.0.0,>=2.1.0->langgraph)\n",
            "  Downloading ormsgpack-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (43 kB)\n",
            "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m43.7/43.7 kB\u001b[0m \u001b[31m2.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25hRequirement already satisfied: orjson>=3.10.1 in /usr/local/lib/python3.11/dist-packages (from langgraph-sdk<0.3.0,>=0.2.0->langgraph) (3.11.2)\n",
            "Requirement already satisfied: requests-toolbelt>=1.0.0 in /usr/local/lib/python3.11/dist-packages (from langsmith>=0.3.8->langmem) (1.0.0)\n",
            "Requirement already satisfied: zstandard>=0.23.0 in /usr/local/lib/python3.11/dist-packages (from langsmith>=0.3.8->langmem) (0.23.0)\n",
            "Requirement already satisfied: annotated-types>=0.6.0 in /usr/local/lib/python3.11/dist-packages (from pydantic>=2.7.4->langgraph) (0.7.0)\n",
            "Requirement already satisfied: pydantic-core==2.33.2 in /usr/local/lib/python3.11/dist-packages (from pydantic>=2.7.4->langgraph) (2.33.2)\n",
            "Requirement already satisfied: typing-inspection>=0.4.0 in /usr/local/lib/python3.11/dist-packages (from pydantic>=2.7.4->langgraph) (0.4.1)\n",
            "Collecting dydantic<1.0.0,>=0.0.8 (from trustcall>=0.0.39->langmem)\n",
            "  Downloading dydantic-0.0.8-py3-none-any.whl.metadata (3.6 kB)\n",
            "Requirement already satisfied: aiohttp in /usr/local/lib/python3.11/dist-packages (from voyageai<1,>=0.3.4->langchain_voyageai) (3.12.15)\n",
            "Collecting aiolimiter (from voyageai<1,>=0.3.4->langchain_voyageai)\n",
            "  Downloading aiolimiter-1.2.1-py3-none-any.whl.metadata (4.5 kB)\n",
            "Requirement already satisfied: pillow in /usr/local/lib/python3.11/dist-packages (from voyageai<1,>=0.3.4->langchain_voyageai) (11.3.0)\n",
            "Requirement already satisfied: tokenizers>=0.14.0 in /usr/local/lib/python3.11/dist-packages (from voyageai<1,>=0.3.4->langchain_voyageai) (0.21.4)\n",
            "Requirement already satisfied: jsonpointer>=1.9 in /usr/local/lib/python3.11/dist-packages (from jsonpatch<2.0,>=1.33->langchain-core>=0.1->langgraph) (3.0.0)\n",
            "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.11/dist-packages (from requests<3,>=2->langchain>=0.3.15->langmem) (3.4.3)\n",
            "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.11/dist-packages (from requests<3,>=2->langchain>=0.3.15->langmem) (2.5.0)\n",
            "Requirement already satisfied: greenlet>=1 in /usr/local/lib/python3.11/dist-packages (from SQLAlchemy<3,>=1.4->langchain>=0.3.15->langmem) (3.2.4)\n",
            "Requirement already satisfied: regex>=2022.1.18 in /usr/local/lib/python3.11/dist-packages (from tiktoken<1,>=0.7->langchain-openai>=0.3.1->langmem) (2024.11.6)\n",
            "Requirement already satisfied: huggingface-hub<1.0,>=0.16.4 in /usr/local/lib/python3.11/dist-packages (from tokenizers>=0.14.0->voyageai<1,>=0.3.4->langchain_voyageai) (0.34.4)\n",
            "Requirement already satisfied: aiohappyeyeballs>=2.5.0 in /usr/local/lib/python3.11/dist-packages (from aiohttp->voyageai<1,>=0.3.4->langchain_voyageai) (2.6.1)\n",
            "Requirement already satisfied: aiosignal>=1.4.0 in /usr/local/lib/python3.11/dist-packages (from aiohttp->voyageai<1,>=0.3.4->langchain_voyageai) (1.4.0)\n",
            "Requirement already satisfied: attrs>=17.3.0 in /usr/local/lib/python3.11/dist-packages (from aiohttp->voyageai<1,>=0.3.4->langchain_voyageai) (25.3.0)\n",
            "Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib/python3.11/dist-packages (from aiohttp->voyageai<1,>=0.3.4->langchain_voyageai) (1.7.0)\n",
            "Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib/python3.11/dist-packages (from aiohttp->voyageai<1,>=0.3.4->langchain_voyageai) (6.6.4)\n",
            "Requirement already satisfied: propcache>=0.2.0 in /usr/local/lib/python3.11/dist-packages (from aiohttp->voyageai<1,>=0.3.4->langchain_voyageai) (0.3.2)\n",
            "Requirement already satisfied: yarl<2.0,>=1.17.0 in /usr/local/lib/python3.11/dist-packages (from aiohttp->voyageai<1,>=0.3.4->langchain_voyageai) (1.20.1)\n",
            "Requirement already satisfied: filelock in /usr/local/lib/python3.11/dist-packages (from huggingface-hub<1.0,>=0.16.4->tokenizers>=0.14.0->voyageai<1,>=0.3.4->langchain_voyageai) (3.18.0)\n",
            "Requirement already satisfied: fsspec>=2023.5.0 in /usr/local/lib/python3.11/dist-packages (from huggingface-hub<1.0,>=0.16.4->tokenizers>=0.14.0->voyageai<1,>=0.3.4->langchain_voyageai) (2025.3.0)\n",
            "Requirement already satisfied: hf-xet<2.0.0,>=1.1.3 in /usr/local/lib/python3.11/dist-packages (from huggingface-hub<1.0,>=0.16.4->tokenizers>=0.14.0->voyageai<1,>=0.3.4->langchain_voyageai) (1.1.7)\n",
            "Downloading langgraph-0.6.5-py3-none-any.whl (153 kB)\n",
            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m153.2/153.2 kB\u001b[0m \u001b[31m6.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25hDownloading langmem-0.0.29-py3-none-any.whl (67 kB)\n",
            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m67.1/67.1 kB\u001b[0m \u001b[31m4.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25hDownloading python_dotenv-1.1.1-py3-none-any.whl (20 kB)\n",
            "Downloading langgraph_checkpoint_mongodb-0.1.4-py3-none-any.whl (11 kB)\n",
            "Downloading pymongo-4.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.4 MB)\n",
            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.4/1.4 MB\u001b[0m \u001b[31m36.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25hDownloading langchain_mongodb-0.6.2-py3-none-any.whl (59 kB)\n",
            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m59.1/59.1 kB\u001b[0m \u001b[31m4.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25hDownloading langgraph_store_mongodb-0.0.1-py3-none-any.whl (8.6 kB)\n",
            "Downloading langchain_voyageai-0.1.7-py3-none-any.whl (6.2 kB)\n",
            "Downloading dnspython-2.7.0-py3-none-any.whl (313 kB)\n",
            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m313.6/313.6 kB\u001b[0m \u001b[31m18.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25hDownloading langchain_anthropic-0.3.18-py3-none-any.whl (29 kB)\n",
            "Downloading langchain_openai-0.3.30-py3-none-any.whl (74 kB)\n",
            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m74.4/74.4 kB\u001b[0m \u001b[31m5.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25hDownloading langgraph_checkpoint-2.1.1-py3-none-any.whl (43 kB)\n",
            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m43.9/43.9 kB\u001b[0m \u001b[31m2.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25hDownloading langgraph_prebuilt-0.6.4-py3-none-any.whl (28 kB)\n",
            "Downloading langgraph_sdk-0.2.0-py3-none-any.whl (50 kB)\n",
            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m50.6/50.6 kB\u001b[0m \u001b[31m3.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25hDownloading lark-1.2.2-py3-none-any.whl (111 kB)\n",
            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m111.0/111.0 kB\u001b[0m \u001b[31m7.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25hDownloading motor-3.7.1-py3-none-any.whl (74 kB)\n",
            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m75.0/75.0 kB\u001b[0m \u001b[31m5.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25hDownloading trustcall-0.0.39-py3-none-any.whl (30 kB)\n",
            "Downloading voyageai-0.3.4-py3-none-any.whl (28 kB)\n",
            "Downloading anthropic-0.64.0-py3-none-any.whl (297 kB)\n",
            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m297.2/297.2 kB\u001b[0m \u001b[31m17.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25hDownloading dydantic-0.0.8-py3-none-any.whl (8.6 kB)\n",
            "Downloading ormsgpack-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (216 kB)\n",
            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m216.5/216.5 kB\u001b[0m \u001b[31m14.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25hDownloading aiolimiter-1.2.1-py3-none-any.whl (6.7 kB)\n",
            "Installing collected packages: python-dotenv, ormsgpack, lark, dnspython, aiolimiter, pymongo, motor, langgraph-sdk, dydantic, anthropic, langgraph-checkpoint, langchain-openai, langchain-anthropic, voyageai, langgraph-prebuilt, langgraph, langchain_voyageai, langchain_mongodb, trustcall, langgraph-store-mongodb, langgraph-checkpoint-mongodb, langmem\n",
            "Successfully installed aiolimiter-1.2.1 anthropic-0.64.0 dnspython-2.7.0 dydantic-0.0.8 langchain-anthropic-0.3.18 langchain-openai-0.3.30 langchain_mongodb-0.6.2 langchain_voyageai-0.1.7 langgraph-0.6.5 langgraph-checkpoint-2.1.1 langgraph-checkpoint-mongodb-0.1.4 langgraph-prebuilt-0.6.4 langgraph-sdk-0.2.0 langgraph-store-mongodb-0.0.1 langmem-0.0.29 lark-1.2.2 motor-3.7.1 ormsgpack-1.10.0 pymongo-4.12.1 python-dotenv-1.1.1 trustcall-0.0.39 voyageai-0.3.4\n"
          ]
        }
      ],
      "source": [
        "!pip install -qU  langgraph langmem pymongo openai python-dotenv typing-extensions langgraph-checkpoint-mongodb langchain_mongodb langgraph-store-mongodb langchain_voyageai"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "5"
      },
      "source": [
        "### Setup API Keys"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "6",
        "outputId": "9042cf95-8bb2-4165-9511-37068aba9be0"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "OpenAI API Key: ··········\n",
            "MongoDB URI: ··········\n",
            "Voyager AI API Key: ··········\n",
            "Voyager AI API Key: ··········\n"
          ]
        }
      ],
      "source": [
        "import getpass\n",
        "import os\n",
        "\n",
        "OPENAI_API_KEY = getpass.getpass(\"OpenAI API Key: \")\n",
        "MONGODB_URI = getpass.getpass(\"MongoDB URI: \")\n",
        "VOYAGE_API_KEY = getpass.getpass(\"VoyageAI API Key: \")\n",
        "\n",
        "os.environ[\"OPENAI_API_KEY\"] = OPENAI_API_KEY\n",
        "os.environ[\"MONGODB_URI\"] = MONGODB_URI\n",
        "os.environ[\"VOYAGE_API_KEY\"] = VOYAGE_API_KEY"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7"
      },
      "source": [
        "### Step 2: Importing Libraries and Setting Up Environment\n",
        "\n",
        "Now, we'll import the necessary modules and set up our API keys for OpenAI and MongoDB. We'll use `python-dotenv` to load credentials from a `.env` file."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {
        "id": "8"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "import sys\n",
        "import typing\n",
        "\n",
        "from dotenv import load_dotenv\n",
        "from langgraph.checkpoint.mongodb import MongoDBSaver\n",
        "from langgraph.prebuilt import create_react_agent\n",
        "from langmem import create_manage_memory_tool\n",
        "from openai import OpenAI\n",
        "from pymongo import MongoClient\n",
        "\n",
        "## import regular tool\n",
        "\n",
        "# Patch for python < 3.11\n",
        "if sys.version_info < (3, 11):\n",
        "    from typing_extensions import NotRequired\n",
        "\n",
        "    typing.NotRequired = NotRequired\n",
        "\n",
        "load_dotenv()\n",
        "\n",
        "# It's recommended to store your keys in a .env file\n",
        "# OPENAI_API_KEY=\"your_openai_api_key\"\n",
        "# MONGO_URI=\"your_mongodb_uri\"\n",
        "\n",
        "client = OpenAI(api_key=os.getenv(\"OPENAI_API_KEY\"))\n",
        "MONGODB_URI = os.environ.get(\"MONGODB_URI\")\n",
        "if not MONGODB_URI:\n",
        "    raise ValueError(\"MONGODB_URI environment variable is not set.\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9"
      },
      "source": [
        "### Loading Data set\n",
        "\n",
        "We will use the \"ai_shop\" catalog dataset which has a product catalog with title, descripition and pricing data."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "metadata": {
        "id": "10"
      },
      "outputs": [],
      "source": [
        "dataset = {\n",
        "    \"train\": [\n",
        "        {\n",
        "            \"title\": \"Spinach Lasagna Sheets\",\n",
        "            \"price\": \"$3.50\",\n",
        "            \"description\": \"Infused with spinach, these sheets add a pop of color and extra nutrients.\",\n",
        "            \"category\": \"Pasta\",\n",
        "            \"emoji\": \"📗\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Gluten-Free Lasagna Sheets\",\n",
        "            \"price\": \"$4.00\",\n",
        "            \"description\": \"Perfect for those with gluten intolerance, made with a blend of rice and corn flour.\",\n",
        "            \"category\": \"Pasta\",\n",
        "            \"emoji\": \"🍚🌽\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Mascarpone\",\n",
        "            \"price\": \"$4.00\",\n",
        "            \"description\": \"Creamy and rich, this cheese adds a luxurious touch to lasagna.\",\n",
        "            \"category\": \"Dairy\",\n",
        "            \"emoji\": \"🧀\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Queso Fresco\",\n",
        "            \"price\": \"$3.00\",\n",
        "            \"description\": \"A mild, crumbly cheese that can be a suitable replacement for ricotta.\",\n",
        "            \"category\": \"Dairy\",\n",
        "            \"emoji\": \"🧀\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Vegetarian Lentil Sauce\",\n",
        "            \"price\": \"$4.00\",\n",
        "            \"description\": \"A meatless option made with cooked lentils that mimics the texture of ground meat.\",\n",
        "            \"category\": \"Vegetarian\",\n",
        "            \"emoji\": \"🍲\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Turkey Bolognese\",\n",
        "            \"price\": \"$5.00\",\n",
        "            \"description\": \"A leaner alternative to beef, turkey provides a lighter but flavorful taste.\",\n",
        "            \"category\": \"Poultry\",\n",
        "            \"emoji\": \"🦃\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Mushroom and Walnut Sauce\",\n",
        "            \"price\": \"$5.50\",\n",
        "            \"description\": \"Combining chopped mushrooms and walnuts for a hearty vegetarian filling.\",\n",
        "            \"category\": \"Vegetarian\",\n",
        "            \"emoji\": \"🍄🥜\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Chicken Bolognese\",\n",
        "            \"price\": \"$5.00\",\n",
        "            \"description\": \"Ground chicken offers a different twist on the classic meat sauce.\",\n",
        "            \"category\": \"Poultry\",\n",
        "            \"emoji\": \"🐔\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Vegan Soy Meat Sauce\",\n",
        "            \"price\": \"$4.50\",\n",
        "            \"description\": \"Made from soy protein, this vegan meat sauce replicates the texture and flavor of traditional meat.\",\n",
        "            \"category\": \"Vegan\",\n",
        "            \"emoji\": \"🌱\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Tomato Basil Sauce\",\n",
        "            \"price\": \"$3.50\",\n",
        "            \"description\": \"A tangy alternative to béchamel, made with fresh tomatoes and basil.\",\n",
        "            \"category\": \"Vegetarian\",\n",
        "            \"emoji\": \"🍅\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Pesto Cream Sauce\",\n",
        "            \"price\": \"$5.50\",\n",
        "            \"description\": \"A fusion of creamy béchamel and rich basil pesto for a unique flavor.\",\n",
        "            \"category\": \"Dairy\",\n",
        "            \"emoji\": \"🍝\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Alfredo Sauce\",\n",
        "            \"price\": \"$4.50\",\n",
        "            \"description\": \"A rich and creamy white sauce made with parmesan and butter.\",\n",
        "            \"category\": \"Dairy\",\n",
        "            \"emoji\": \"🧈\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Coconut Milk Béchamel\",\n",
        "            \"price\": \"$4.00\",\n",
        "            \"description\": \"A dairy-free version of the classic béchamel made with coconut milk.\",\n",
        "            \"category\": \"Vegan\",\n",
        "            \"emoji\": \"🥥\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Vegan Cashew Cream Sauce\",\n",
        "            \"price\": \"$5.00\",\n",
        "            \"description\": \"A rich and creamy sauce made from blended cashews as a dairy-free alternative.\",\n",
        "            \"category\": \"Vegan\",\n",
        "            \"emoji\": \"🥜\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Kale\",\n",
        "            \"price\": \"$2.00\",\n",
        "            \"description\": \"Another leafy green option, kale offers a chewy texture and rich nutrients.\",\n",
        "            \"category\": \"Leafy Greens\",\n",
        "            \"emoji\": \"🥬\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Bell Peppers\",\n",
        "            \"price\": \"$2.50\",\n",
        "            \"description\": \"Sliced bell peppers in various colors add sweetness and crunch.\",\n",
        "            \"category\": \"Vegetables\",\n",
        "            \"emoji\": \"🫑\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Artichoke Hearts\",\n",
        "            \"price\": \"$3.50\",\n",
        "            \"description\": \"Tender and flavorful, artichoke hearts bring a Mediterranean twist to the dish.\",\n",
        "            \"category\": \"Vegetables\",\n",
        "            \"emoji\": \"🍽️\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Spinach\",\n",
        "            \"price\": \"$2.00\",\n",
        "            \"description\": \"Fresh or frozen spinach adds a pop of color and nutrients.\",\n",
        "            \"category\": \"Leafy Greens\",\n",
        "            \"emoji\": \"🥬\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Broccoli\",\n",
        "            \"price\": \"$2.50\",\n",
        "            \"description\": \"Small broccoli florets provide texture and a distinct flavor.\",\n",
        "            \"category\": \"Vegetables\",\n",
        "            \"emoji\": \"🥦\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Whole Wheat Lasagna Sheets\",\n",
        "            \"price\": \"$3.00\",\n",
        "            \"description\": \"Made from whole wheat grains, these sheets are healthier and provide a nutty flavor.\",\n",
        "            \"category\": \"Pasta\",\n",
        "            \"emoji\": \"🌾\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Zucchini Slices\",\n",
        "            \"price\": \"$2.50\",\n",
        "            \"description\": \"Thinly sliced zucchini can replace traditional pasta for a low-carb version.\",\n",
        "            \"category\": \"Vegetables\",\n",
        "            \"emoji\": \"🥒\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Eggplant Slices\",\n",
        "            \"price\": \"$2.75\",\n",
        "            \"description\": \"Thin slices of eggplant provide a meaty texture, ideal for vegetarian lasagna.\",\n",
        "            \"category\": \"Vegetables\",\n",
        "            \"emoji\": \"🍆\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Ground Turkey\",\n",
        "            \"price\": \"$4.50\",\n",
        "            \"description\": \"A leaner alternative to beef, turkey provides a lighter but flavorful taste.\",\n",
        "            \"category\": \"Meat\",\n",
        "            \"emoji\": \"🦃\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Vegetarian Lentil Mince\",\n",
        "            \"price\": \"$3.50\",\n",
        "            \"description\": \"A meatless option made with cooked lentils that mimics the texture of ground meat.\",\n",
        "            \"category\": \"Vegetarian\",\n",
        "            \"emoji\": \"🍲\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Mushroom and Walnut Mince\",\n",
        "            \"price\": \"$5.00\",\n",
        "            \"description\": \"Combining chopped mushrooms and walnuts for a hearty vegetarian filling.\",\n",
        "            \"category\": \"Vegetarian\",\n",
        "            \"emoji\": \"🍄🥜\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Ground Chicken\",\n",
        "            \"price\": \"$4.00\",\n",
        "            \"description\": \"Ground chicken offers a different twist on the classic meat sauce.\",\n",
        "            \"category\": \"Poultry\",\n",
        "            \"emoji\": \"🐔\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Vegan Soy Meat Crumbles\",\n",
        "            \"price\": \"$4.50\",\n",
        "            \"description\": \"Made from soy protein, these crumbles replicate the texture and flavor of traditional meat.\",\n",
        "            \"category\": \"Vegan\",\n",
        "            \"emoji\": \"🥩\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Pesto Sauce\",\n",
        "            \"price\": \"$4.00\",\n",
        "            \"description\": \"A green, aromatic sauce made from basil, pine nuts, and garlic.\",\n",
        "            \"category\": \"Canned Goods\",\n",
        "            \"emoji\": \"🌿\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Marinara Sauce\",\n",
        "            \"price\": \"$3.50\",\n",
        "            \"description\": \"A classic Italian tomato sauce with garlic, onions, and herbs.\",\n",
        "            \"category\": \"Canned Goods\",\n",
        "            \"emoji\": \"🍅\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Bolognese Sauce\",\n",
        "            \"price\": \"$5.00\",\n",
        "            \"description\": \"A meat-based sauce simmered with tomatoes, onions, celery, and carrots.\",\n",
        "            \"category\": \"Canned Goods\",\n",
        "            \"emoji\": \"🍖🍅🧅🥕\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Arrabbiata Sauce\",\n",
        "            \"price\": \"$4.00\",\n",
        "            \"description\": \"A spicy tomato sauce made with red chili peppers.\",\n",
        "            \"category\": \"Canned Goods\",\n",
        "            \"emoji\": \"🌶️🍅\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Provolone Cheese\",\n",
        "            \"price\": \"$3.50\",\n",
        "            \"description\": \"Semi-hard cheese with a smooth texture, it melts beautifully in dishes.\",\n",
        "            \"category\": \"Dairy\",\n",
        "            \"emoji\": \"🧀\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Cheddar Cheese\",\n",
        "            \"price\": \"$3.00\",\n",
        "            \"description\": \"A popular cheese with a sharp and tangy flavor profile.\",\n",
        "            \"category\": \"Dairy\",\n",
        "            \"emoji\": \"🧀\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Gouda Cheese\",\n",
        "            \"price\": \"$4.50\",\n",
        "            \"description\": \"A Dutch cheese known for its rich and creamy texture.\",\n",
        "            \"category\": \"Dairy\",\n",
        "            \"emoji\": \"🧀\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Fontina Cheese\",\n",
        "            \"price\": \"$4.00\",\n",
        "            \"description\": \"A semi-soft cheese with a strong flavor, great for melting.\",\n",
        "            \"category\": \"Dairy\",\n",
        "            \"emoji\": \"🧀\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Vegan Mozzarella\",\n",
        "            \"price\": \"$5.00\",\n",
        "            \"description\": \"Dairy-free alternative made from nuts or soy, melts similarly to regular mozzarella.\",\n",
        "            \"category\": \"Vegan\",\n",
        "            \"emoji\": \"🧀\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Cottage Cheese\",\n",
        "            \"price\": \"$2.50\",\n",
        "            \"description\": \"A lighter alternative to ricotta, with small curds that provide a similar texture.\",\n",
        "            \"category\": \"Dairy\",\n",
        "            \"emoji\": \"🧀\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Goat Cheese\",\n",
        "            \"price\": \"$4.00\",\n",
        "            \"description\": \"A tangy and creamy cheese that can provide a unique flavor to lasagna.\",\n",
        "            \"category\": \"Dairy\",\n",
        "            \"emoji\": \"🧀\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Mascarpone Cheese\",\n",
        "            \"price\": \"$4.50\",\n",
        "            \"description\": \"An Italian cream cheese with a rich and creamy texture.\",\n",
        "            \"category\": \"Dairy\",\n",
        "            \"emoji\": \"🧀\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Tofu Ricotta\",\n",
        "            \"price\": \"$3.00\",\n",
        "            \"description\": \"A vegan alternative made from crumbled tofu seasoned with herbs.\",\n",
        "            \"category\": \"Vegan\",\n",
        "            \"emoji\": \"🌱\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Feta Cheese\",\n",
        "            \"price\": \"$3.50\",\n",
        "            \"description\": \"A crumbly cheese with a salty profile, it can bring a Mediterranean twist to the dish.\",\n",
        "            \"category\": \"Dairy\",\n",
        "            \"emoji\": \"🧀\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Parmesan cheese\",\n",
        "            \"price\": \"$4.00\",\n",
        "            \"description\": \"A hard, granular cheese originating from Italy, known for its rich umami flavor.\",\n",
        "            \"category\": \"Dairy\",\n",
        "            \"emoji\": \"🧀\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Pecorino Romano\",\n",
        "            \"price\": \"$5.00\",\n",
        "            \"description\": \"A salty, hard cheese made from sheep's milk, perfect for grating over dishes.\",\n",
        "            \"category\": \"Dairy\",\n",
        "            \"emoji\": \"🧀\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Asiago Cheese\",\n",
        "            \"price\": \"$4.50\",\n",
        "            \"description\": \"Semi-hard cheese with a nutty flavor, great for shaving or grating.\",\n",
        "            \"category\": \"Dairy\",\n",
        "            \"emoji\": \"🧀\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Grana Padano\",\n",
        "            \"price\": \"$5.50\",\n",
        "            \"description\": \"A grainy, hard cheese that's similar to Parmesan but milder in flavor.\",\n",
        "            \"category\": \"Dairy\",\n",
        "            \"emoji\": \"🧀\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Manchego Cheese\",\n",
        "            \"price\": \"$6.00\",\n",
        "            \"description\": \"A Spanish hard cheese with a rich and nutty flavor.\",\n",
        "            \"category\": \"Dairy\",\n",
        "            \"emoji\": \"🧀\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Eggs\",\n",
        "            \"price\": \"$2.00\",\n",
        "            \"description\": \"Rich in protein and versatile, eggs are used in a variety of culinary applications.\",\n",
        "            \"category\": \"Dairy\",\n",
        "            \"emoji\": \"🥚\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Tofu\",\n",
        "            \"price\": \"$2.00\",\n",
        "            \"description\": \"Blended silken tofu can act as a binder in various dishes.\",\n",
        "            \"category\": \"Vegan\",\n",
        "            \"emoji\": \"🍲\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Flaxseed Meal\",\n",
        "            \"price\": \"$1.50\",\n",
        "            \"description\": \"Mix with water to create a gel-like consistency that can replace eggs.\",\n",
        "            \"category\": \"Vegan\",\n",
        "            \"emoji\": \"🥚\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Chia Seeds\",\n",
        "            \"price\": \"$2.50\",\n",
        "            \"description\": \"Mix with water to form a gel that can be used as an egg substitute.\",\n",
        "            \"category\": \"Vegan\",\n",
        "            \"emoji\": \"🥚\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Apple Sauce\",\n",
        "            \"price\": \"$2.00\",\n",
        "            \"description\": \"A sweet alternative that can replace eggs in certain recipes.\",\n",
        "            \"category\": \"Baking\",\n",
        "            \"emoji\": \"🥚\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Onion\",\n",
        "            \"price\": \"$1.00\",\n",
        "            \"description\": \"A kitchen staple, onions provide depth and flavor to a myriad of dishes.\",\n",
        "            \"category\": \"Vegetables\",\n",
        "            \"emoji\": \"🧅\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Shallots\",\n",
        "            \"price\": \"$2.00\",\n",
        "            \"description\": \"Milder and sweeter than regular onions, they add a delicate flavor.\",\n",
        "            \"category\": \"Produce\",\n",
        "            \"emoji\": \"🧅\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Green Onions\",\n",
        "            \"price\": \"$1.50\",\n",
        "            \"description\": \"Milder in flavor, green onions or scallions are great for garnishing.\",\n",
        "            \"category\": \"Vegetables\",\n",
        "            \"emoji\": \"🌱\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Red Onion\",\n",
        "            \"price\": \"$1.20\",\n",
        "            \"description\": \"Sweeter and more vibrant in color, red onions add a pop to dishes.\",\n",
        "            \"category\": \"Vegetables\",\n",
        "            \"emoji\": \"🔴\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Leeks\",\n",
        "            \"price\": \"$2.50\",\n",
        "            \"description\": \"With a light onion flavor, leeks are great when sautéed or used in soups.\",\n",
        "            \"category\": \"Produce\",\n",
        "            \"emoji\": \"🍲\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Garlic\",\n",
        "            \"price\": \"$0.50\",\n",
        "            \"description\": \"Aromatic and flavorful, garlic is a foundational ingredient in many cuisines.\",\n",
        "            \"category\": \"Produce\",\n",
        "            \"emoji\": \"🧄\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Garlic Powder\",\n",
        "            \"price\": \"$2.00\",\n",
        "            \"description\": \"A convenient dried version of garlic that provides a milder flavor.\",\n",
        "            \"category\": \"Spices\",\n",
        "            \"emoji\": \"🧄\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Garlic Flakes\",\n",
        "            \"price\": \"$2.50\",\n",
        "            \"description\": \"Dried garlic flakes can be rehydrated or used as they are for a burst of garlic flavor.\",\n",
        "            \"category\": \"Spices\",\n",
        "            \"emoji\": \"🧄\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Garlic Paste\",\n",
        "            \"price\": \"$3.00\",\n",
        "            \"description\": \"A smooth blend of garlic, perfect for adding to sauces or marinades.\",\n",
        "            \"category\": \"Condiments\",\n",
        "            \"emoji\": \"🧄\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Olive Oil\",\n",
        "            \"price\": \"$6.00\",\n",
        "            \"description\": \"A staple in Mediterranean cuisine, olive oil is known for its heart-healthy properties.\",\n",
        "            \"category\": \"Condiments\",\n",
        "            \"emoji\": \"🍽️\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Canola Oil\",\n",
        "            \"price\": \"$3.50\",\n",
        "            \"description\": \"A neutral-tasting oil suitable for various cooking methods.\",\n",
        "            \"category\": \"Condiments\",\n",
        "            \"emoji\": \"🍳\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Coconut Oil\",\n",
        "            \"price\": \"$5.00\",\n",
        "            \"description\": \"A fragrant oil ideal for sautéing and baking.\",\n",
        "            \"category\": \"Condiments\",\n",
        "            \"emoji\": \"🍳\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Avocado Oil\",\n",
        "            \"price\": \"$7.00\",\n",
        "            \"description\": \"Known for its high smoke point, it's great for high-heat cooking.\",\n",
        "            \"category\": \"Condiments\",\n",
        "            \"emoji\": \"🍳\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Grapeseed Oil\",\n",
        "            \"price\": \"$6.50\",\n",
        "            \"description\": \"A light, neutral oil that's good for dressings and sautéing.\",\n",
        "            \"category\": \"Condiments\",\n",
        "            \"emoji\": \"🥗\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Salt\",\n",
        "            \"price\": \"$1.00\",\n",
        "            \"description\": \"An essential seasoning that enhances the flavor of dishes.\",\n",
        "            \"category\": \"Spices\",\n",
        "            \"emoji\": \"🧂\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Himalayan Pink Salt\",\n",
        "            \"price\": \"$2.50\",\n",
        "            \"description\": \"A natural and unrefined salt with a slightly earthy flavor.\",\n",
        "            \"category\": \"Spices\",\n",
        "            \"emoji\": \"🧂\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Sea Salt\",\n",
        "            \"price\": \"$2.00\",\n",
        "            \"description\": \"Derived from evaporated seawater, it provides a briny touch.\",\n",
        "            \"category\": \"Spices\",\n",
        "            \"emoji\": \"🌊\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Kosher Salt\",\n",
        "            \"price\": \"$1.50\",\n",
        "            \"description\": \"A coarse salt without additives, commonly used in cooking.\",\n",
        "            \"category\": \"Spices\",\n",
        "            \"emoji\": \"🧂\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Black Salt (Kala Namak)\",\n",
        "            \"price\": \"$2.00\",\n",
        "            \"description\": \"A sulfurous salt often used in South Asian cuisine, especially vegan dishes to mimic an eggy flavor.\",\n",
        "            \"category\": \"Spices\",\n",
        "            \"emoji\": \"🧂\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Black Pepper\",\n",
        "            \"price\": \"$2.00\",\n",
        "            \"description\": \"A versatile spice known for its sharp and mildly spicy flavor.\",\n",
        "            \"category\": \"Spices\",\n",
        "            \"emoji\": \"🌶️\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"White Pepper\",\n",
        "            \"price\": \"$2.50\",\n",
        "            \"description\": \"Milder than black pepper, it's often used in light-colored dishes.\",\n",
        "            \"category\": \"Spices\",\n",
        "            \"emoji\": \"🌶️\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Cayenne Pepper\",\n",
        "            \"price\": \"$2.00\",\n",
        "            \"description\": \"A spicy chili pepper, ground into powder. Adds heat to dishes.\",\n",
        "            \"category\": \"Spices\",\n",
        "            \"emoji\": \"🌶️\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Crushed Red Pepper Flakes\",\n",
        "            \"price\": \"$1.50\",\n",
        "            \"description\": \"Adds a spicy kick to dishes, commonly used as a pizza topping.\",\n",
        "            \"category\": \"Spices\",\n",
        "            \"emoji\": \"🌶️\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Sichuan (or Szechuan) Peppercorns\",\n",
        "            \"price\": \"$3.00\",\n",
        "            \"description\": \"Known for their unique tingling sensation, they're used in Chinese cuisine.\",\n",
        "            \"category\": \"Spices\",\n",
        "            \"emoji\": \"🥡\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Banana\",\n",
        "            \"price\": \"$0.60\",\n",
        "            \"description\": \"A sweet and portable fruit, packed with essential vitamins.\",\n",
        "            \"category\": \"Produce\",\n",
        "            \"emoji\": \"🍌\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Milk\",\n",
        "            \"price\": \"$2.50\",\n",
        "            \"description\": \"A calcium-rich dairy product, perfect for drinking or cooking.\",\n",
        "            \"category\": \"Dairy\",\n",
        "            \"emoji\": \"🥛\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Bread\",\n",
        "            \"price\": \"$2.00\",\n",
        "            \"description\": \"Freshly baked, perfect for sandwiches or toast.\",\n",
        "            \"category\": \"Bakery\",\n",
        "            \"emoji\": \"🍞\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Apple\",\n",
        "            \"price\": \"$1.00\",\n",
        "            \"description\": \"Crisp and juicy, great for snacking or baking.\",\n",
        "            \"category\": \"Produce\",\n",
        "            \"emoji\": \"🍏\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Orange\",\n",
        "            \"price\": \"3.99$\",\n",
        "            \"description\": \"Great as a juice and vitamin\",\n",
        "            \"category\": \"Produce\",\n",
        "            \"emoji\": \"🍊\",\n",
        "        },\n",
        "        {\n",
        "            \"title\": \"Sugar\",\n",
        "            \"price\": \"1.00\",\n",
        "            \"description\": \"very sweet substance\",\n",
        "            \"category\": \"Spices\",\n",
        "            \"emoji\": \"🍰\",\n",
        "        },\n",
        "    ]\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "11"
      },
      "source": [
        "### Load the data and create vector store index.\n",
        "\n",
        "We will use a langchain vector store adapter to load and embed our catalog. This will allow the agent to search for relevant products from our database."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "12",
        "outputId": "72fc180b-c998-4a1e-bcd1-d2ed08ac668b"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Database seeded successfully!\n"
          ]
        }
      ],
      "source": [
        "from langchain_core.documents import Document\n",
        "from langchain_mongodb.vectorstores import MongoDBAtlasVectorSearch\n",
        "from langchain_voyageai import VoyageAIEmbeddings\n",
        "\n",
        "# Assuming dataset is already loaded as shown in the previous cells\n",
        "docs = [\n",
        "    Document(page_content=f\"{item['title']} - {item['description']}\", metadata=item)\n",
        "    for item in dataset[\"train\"]\n",
        "]\n",
        "\n",
        "# Initialize the vector store\n",
        "vector_store = MongoDBAtlasVectorSearch.from_connection_string(\n",
        "    connection_string=MONGODB_URI,\n",
        "    namespace=\"ai_shop.products\",\n",
        "    embedding=VoyageAIEmbeddings(model=\"voyage-3.5\"),\n",
        "    index_name=\"vector_index\",\n",
        ")\n",
        "\n",
        "client = MongoClient(MONGODB_URI)\n",
        "db = client[\"ai_shop\"]\n",
        "collection = db[\"products\"]\n",
        "\n",
        "collection.delete_many({})\n",
        "\n",
        "# Add documents to the vector store\n",
        "vector_store.add_documents(documents=docs)\n",
        "\n",
        "# Create the Atlas Vector Index\n",
        "vector_store.create_vector_search_index(dimensions=1024, wait_until_complete=70)\n",
        "\n",
        "print(\"Database seeded successfully!\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "13"
      },
      "source": [
        "### Part 2: Core Components Explained\n",
        "\n",
        "Our agent has a few key parts:\n",
        "\n",
        "- **`MongoDBStore`**: This is where the agent's \"memories\" are stored for fast retrieval using vector search. It's great for semantic search with persistant nature.\n",
        "- **`MongoDBSaver`**: This acts as a checkpointer. It saves the entire conversation state (including messages) to a MongoDB database, ensuring durability and allowing conversations to be resumed.\n",
        "- **`create_manage_memory_tool`**: This tool, provided by `langmem`, gives the agent the ability to create, update, and delete memories in its `MongoDBStore`.\n",
        "- **`prompt` function**: This function dynamically injects relevant memories from the `MongoDBStore` into the agent's system prompt, giving it context for its responses."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "metadata": {
        "id": "14"
      },
      "outputs": [],
      "source": [
        "def prompt(state, store):\n",
        "    \"\"\"Prepare the messages for the LLM by injecting memories.\"\"\"\n",
        "    memories = store.search(\n",
        "        (\"memories\",),\n",
        "        query=state[\"messages\"][-1].content,\n",
        "    )\n",
        "    system_msg = f\"\"\"You are a shopping assistant that have access to search_products tool and memory\n",
        "\n",
        "## Memories\n",
        "\n",
        "<memories>\n",
        "{memories}\n",
        "</memories>\n",
        "\n",
        "\"\"\"\n",
        "    return [{\"role\": \"system\", \"content\": system_msg}, *state[\"messages\"]]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "15"
      },
      "source": [
        "### Part 3: Building and Running the Agent\n",
        "We will leverge [`MongoDBStore`](https://langchain-mongodb.readthedocs.io/en/latest/langgraph_store_mongodb/base/langgraph.store.mongodb.base.MongoDBStore.html#langgraph.store.mongodb.base.MongoDBStore) to form a long term memory, this component will leverge semantic (vector) search to remember and fetch memories."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "metadata": {
        "id": "16"
      },
      "outputs": [],
      "source": [
        "# 1. Initialize the graph store for vector search\n",
        "\n",
        "from langchain_core.tools import tool  # Import tool decorator\n",
        "from langchain_mongodb.vectorstores import (\n",
        "    MongoDBAtlasVectorSearch,\n",
        ")  # Import necessary class\n",
        "from langchain_voyageai import VoyageAIEmbeddings\n",
        "from langgraph.store.mongodb.base import (\n",
        "    MongoDBStore,\n",
        "    VectorIndexConfig,\n",
        ")  # Import MongoDBStore\n",
        "\n",
        "# 2. Initialize the MongoDB checkpointer for conversation history\n",
        "\n",
        "client = MongoClient(MONGODB_URI)\n",
        "db = client[\"memories\"]\n",
        "collection = db[\"memory_store\"]\n",
        "\n",
        "# Create store directly\n",
        "store = MongoDBStore(\n",
        "    collection=collection,\n",
        "    index_config=VectorIndexConfig(\n",
        "        fields=None,\n",
        "        filters=None,\n",
        "        dims=1024,\n",
        "        embed=VoyageAIEmbeddings(\n",
        "            model=\"voyage-3.5\"\n",
        "        ),  # Pass an instance of OpenAIEmbeddings\n",
        "    ),\n",
        "    auto_index_timeout=70,\n",
        ")\n",
        "\n",
        "\n",
        "## Add tool function for vector search\n",
        "@tool\n",
        "def search_products(query: str) -> str:\n",
        "    \"\"\"Searches for products in the database using vector search.\"\"\"\n",
        "    db = client[\"ai_shop\"]\n",
        "    collection = db[\"products\"]\n",
        "    vectorstore = MongoDBAtlasVectorSearch(\n",
        "        collection,\n",
        "        VoyageAIEmbeddings(model=\"voyage-3.5\"),\n",
        "        text_key=\"title\",\n",
        "        embedding_key=\"embedding\",\n",
        "        index_name=\"vector_index\",\n",
        "    )\n",
        "    docs = vectorstore.similarity_search(query, k=5)\n",
        "\n",
        "    return \"\\n\".join([str(doc.metadata) for doc in docs])\n",
        "\n",
        "\n",
        "checkpointer = MongoDBSaver(\n",
        "    client, db_name=\"memories\", collection_name=\"thread_checkpoints\"\n",
        ")\n",
        "\n",
        "# 3. Create the agent with the memory tool\n",
        "agent = create_react_agent(\n",
        "    \"openai:gpt-4o\",\n",
        "    prompt=lambda state: prompt(state, store),  # Pass the store to the prompt function\n",
        "    tools=[\n",
        "        create_manage_memory_tool(namespace=(\"memories\",)),\n",
        "        search_products,  # Add the new tool here\n",
        "    ],\n",
        "    store=store,\n",
        "    checkpointer=checkpointer,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "17"
      },
      "source": [
        "#### Demonstration\n",
        "\n",
        "Let's start a conversation. We use a `thread_id` to manage conversation state. The agent has no memories of us yet."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "18",
        "outputId": "d9e455ad-9e03-4927-bade-3ea63bd359ce"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Here's a selection of ingredients for making lasagne, including prices:\n",
            "\n",
            "### Lasagne Noodles\n",
            "- **Whole Wheat Lasagna Sheets**: $3.00 🍖  \n",
            "- **Gluten-Free Lasagna Sheets**: $4.00 🍚  \n",
            "- **Spinach Lasagna Sheets**: $3.50 🥬  \n",
            "- **Eggplant Slices** (for vegetarian option): $2.75 🍆  \n",
            "\n",
            "### Ground Beef (or alternatives)\n",
            "- **Ground Turkey**: $4.50 🍗  \n",
            "- **Ground Chicken**: $4.00 🐔  \n",
            "- **Vegetarian Lentil Mince**: $3.50 🍲  \n",
            "\n",
            "### Tomato Sauce\n",
            "- **Marinara Sauce**: $3.50 🍅  \n",
            "- **Arrabbiata Sauce**: $4.00 🌶️🍅  \n",
            "- **Tomato Basil Sauce**: $3.50 🍅🌿  \n",
            "\n",
            "### Ricotta Cheese (or alternatives)\n",
            "- **Queso Fresco**: $3.00 🧀  \n",
            "- **Cottage Cheese**: $2.50 🧀  \n",
            "- **Tofu Ricotta**: $3.00 🌱  \n",
            "\n",
            "### Mozzarella Cheese (or alternatives)\n",
            "- **Vegan Mozzarella**: $5.00 🧀  \n",
            "- **Provolone Cheese**: $3.50 🧀  \n",
            "- **Fontina Cheese**: $4.00 🧀  \n",
            "\n",
            "### Parmesan Cheese (or alternatives)\n",
            "- **Parmesan Cheese**: $4.00 🧀  \n",
            "- **Grana Padano**: $5.50 🧀  \n",
            "- **Pecorino Romano**: $5.00 🧀  \n",
            "\n",
            "### Garlic\n",
            "- **Garlic**: $0.50 🧄  \n",
            "- **Garlic Paste**: $3.00 🧄  \n",
            "- **Garlic Flakes**: $2.50 🧄  \n",
            "\n",
            "### Onion\n",
            "- **Red Onion**: $1.20 🟥  \n",
            "- **Regular Onion**: $1.00 🧅  \n",
            "- **Shallots**: $2.00 🧅  \n",
            "\n",
            "### Basil\n",
            "- **Pesto Sauce** (includes basil): $4.00 🌿  \n",
            "\n",
            "### Oregano\n",
            "- Found in various seasoning mixes.  \n",
            "\n",
            "## Total Cost for Basic Ingredients:\n",
            "Assuming you select the first option for each category, the total would be approximately **$24.70**.\n",
            "\n",
            "Feel free to choose different options to suit dietary requirements or preferences!\n"
          ]
        }
      ],
      "source": [
        "config = {\"configurable\": {\"thread_id\": \"thread-a\"}}\n",
        "\n",
        "response = agent.invoke(\n",
        "    {\n",
        "        \"messages\": [\n",
        "            {\n",
        "                \"role\": \"user\",\n",
        "                \"content\": \"What is my diet preference? I need help on finding ingiridiants for a lasagne, search the database for each ingridiant seperatly and provide overall total\",\n",
        "            }\n",
        "        ]\n",
        "    },\n",
        "    config=config,\n",
        ")\n",
        "print(response[\"messages\"][-1].content)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "19"
      },
      "source": [
        "Now, let's tell the agent our preference. The agent will use the `manage_memory` tool to save this information."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "20",
        "outputId": "e13ac8a4-92c3-4199-b0d4-9b75ffd7cda0"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "I've noted that you follow a vegan diet. Here is the recalculated total with vegan ingredients, assuming one option for each category:\n",
            "\n",
            "### Vegan Ingredients Selection\n",
            "1. **Lasagne Noodles:** Whole Wheat Lasagna Sheets - $3.00\n",
            "2. **Ground Beef Alternative:** Vegan Soy Meat Crumbles - $4.50\n",
            "3. **Tomato Sauce:** Marinara Sauce - $3.50\n",
            "4. **Ricotta Cheese Alternative:** Tofu Ricotta - $3.00\n",
            "5. **Mozzarella Cheese Alternative:** Vegan Mozzarella - $5.00\n",
            "6. **Parmesan Cheese Alternative:** Vegan Cashew Cream Sauce - $5.00\n",
            "7. **Garlic:** Garlic - $0.50\n",
            "8. **Onion:** Regular Onion - $1.00\n",
            "9. **Basil:** Pesto Sauce - $4.00\n",
            "\n",
            "### Total Cost\n",
            "**$29.50**\n",
            "\n",
            "This total accounts for using vegan products to ensure your dietary preferences are accommodated. Let me know if you need any further assistance!\n"
          ]
        }
      ],
      "source": [
        "response = agent.invoke(\n",
        "    {\n",
        "        \"messages\": [\n",
        "            {\"role\": \"user\", \"content\": \"Remember I am vegan. Please recalculate\"}\n",
        "        ]\n",
        "    },\n",
        "    config=config,\n",
        ")\n",
        "\n",
        "## Show tool calls\n",
        "print(response[\"messages\"][-1].content)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "21"
      },
      "source": [
        "If we ask again in the same conversation thread, it should remember."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "22",
        "outputId": "22892970-fc9e-40f5-c02d-dee6cb2ad33d"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "The selection I provided aligns with a vegan diet because it excludes all animal products, including meat, dairy, and eggs. Here’s how:\n",
            "\n",
            "1. **Lasagne Noodles:** Options include eggplant slices, zucchini slices, and whole wheat or gluten-free lasagna sheets, which are all plant-based.\n",
            "\n",
            "2. **Ground Beef Alternative:** I selected vegan soy meat crumbles, ensuring the texture and protein source are plant-derived.\n",
            "\n",
            "3. **Tomato Sauce:** Marinara and vegan sauces like cashew cream are plant-based and free from dairy.\n",
            "\n",
            "4. **Ricotta Cheese Alternative:** Tofu Ricotta is used instead of traditional ricotta cheese, providing a vegan-friendly option.\n",
            "\n",
            "5. **Mozzarella Cheese Alternative:** Vegan mozzarella, made from nuts or soy, replaces conventional mozzarella.\n",
            "\n",
            "6. **Parmesan Cheese Alternative:** The use of vegan cashew cream sauce offers a dairy-free replacement to parmesan.\n",
            "\n",
            "7. **Garlic and Onion:** These are naturally vegan and provide flavor without animal products.\n",
            "\n",
            "8. **Herbs:** Basil, via vegan pesto sauce, complements the dish without any animal-derived ingredients.\n",
            "\n",
            "Overall, each ingredient chosen fits within a vegan framework by either being inherently plant-based or replaced with a vegan alternative, supporting your dietary preferences.\n"
          ]
        }
      ],
      "source": [
        "response = agent.invoke(\n",
        "    {\"messages\": [{\"role\": \"user\", \"content\": \"So how is this aligned with my diet?\"}]},\n",
        "    config=config,\n",
        ")\n",
        "print(response[\"messages\"][-1].content)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "23"
      },
      "source": [
        "Now, let's start a new conversation with a different `thread_id`. The agent will remeber us in this new thread, because the memories are scoped not scoped to a conversation."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "24",
        "outputId": "4a998384-6a14-4860-b2b3-4e4da29a7b99"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Yes, I remember you follow a vegan diet. If there's anything else you'd like to update or add, feel free to let me know!\n"
          ]
        }
      ],
      "source": [
        "new_config = {\"configurable\": {\"thread_id\": \"thread-b\"}}\n",
        "\n",
        "response = agent.invoke(\n",
        "    {\n",
        "        \"messages\": [\n",
        "            {\n",
        "                \"role\": \"user\",\n",
        "                \"content\": \"Hey there. Do you remember me? What is my diet preference?\",\n",
        "            }\n",
        "        ]\n",
        "    },\n",
        "    config=new_config,\n",
        ")\n",
        "print(response[\"messages\"][-1].content)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "25"
      },
      "source": [
        "### ⛳ Knowledge Checkpoint\n",
        "\n",
        "You've now seen how to:\n",
        "\n",
        "- **Create a stateful agent** using `langgraph`.\n",
        "- **Use `langmem`** to provide the agent with tools to manage its own memory.\n",
        "- **Leverage MongoDB** with `MongoDBSaver` and `MongoDBStore` to persist conversation history and long-term memory, making your agent durable with memory mechanisim."
      ]
    }
  ],
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.8.5"
    },
    "widgets": {
      "application/vnd.jupyter.widget-state+json": {
        "state": {}
      }
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
